Back to Courses
PYTHON API AUTOMATION — REQUESTS · PYTEST · CONFIG.INI · ALLURE · GITHUB REST API

API Automation with Python —
Build a Production-Ready Framework from Scratch

Master the requests library, all HTTP methods, Bearer token auth, pytest markers, base class architecture, config.ini multi-environment, and Allure Reports — hands-on with GitHub's real REST API throughout.

20+
Days of Training
12
Modules
70+
Topics Covered
Python
REST API

Who Is This Course For?

Built for manual testers who know REST API concepts and have used Postman, and now want to write Python code that automates API testing end-to-end — with a professional framework, multi-environment config, and Allure reports.

REST API Concepts Postman Experience Python Basics GitHub Account

Your Learning Journey

API Concepts & REST
Python + requests Setup
HTTP Methods
Auth & Headers
JSON Assertions
GitHub API Practice
pytest Framework
Base Class + config.ini
Allure Reports
Full Framework + Interview
MODULE 01
API Testing Fundamentals
REST · HTTP methods · status codes · Postman · request anatomy · API vs UI testing
WHY THIS MODULE

You can't automate what you don't understand. Before writing a single line of Python, you need to know exactly how an API works — the request, the response, the status codes, and the HTTP methods. This module also explains why API tests run 100x faster than UI tests, which is the core reason companies invest so heavily in API automation and why this skill is so valuable in the job market.

REST API Concepts
  • Client-Server architecture — request and response cycle
  • HTTP methods: GET, POST, PUT, PATCH, DELETE
  • Status codes — 200, 201, 401, 404, 422, 500
  • Request anatomy: URL, headers, body, query params
  • REST vs SOAP — when to use each
  • JSON structure — objects, arrays, nested keys
API Testing in Practice
  • API tests are faster than UI — 2,000 scenarios run in minutes, not hours
  • API testing in the test pyramid — contract, functional, integration layers
  • Postman — explore and manually test APIs before automating
  • Import collections, set environment variables in Postman
MODULE 02
Python & Environment Setup
Python 3 · PyCharm · pip · venv · requests library · response.json()
WHY THIS MODULE

The right setup from the start saves days of frustration. A virtual environment keeps your project's libraries isolated so upgrading one project never breaks another. Installing requests correctly and making your first successful API call in code is the moment automation clicks — you see data from a real server appear in your Python output, and from that point the whole course builds on top of it.

Python & IDE Setup
  • Install Python 3.x — understand major vs minor versions
  • PyCharm Community Edition — create and manage a Python project
  • Virtual environment (venv) — isolated library space per project
  • pip install requests — install the requests library
First API Call
  • response = requests.get(url) — send your first GET
  • response.status_code, response.json(), response.headers
  • Parse and print nested JSON values
  • Python dict, list, f-string essentials for API testing
MODULE 03
GET Requests — Query Params, Path Params & Pagination
params dict · path params · f-string URL · pagination · json.dumps()
WHY THIS MODULE

Most real API test bugs come from not knowing how to properly pass parameters. Confusing a query param with a path param, or hardcoding a page number instead of using a variable — these are mistakes that break entire test suites. Understanding pagination is also important because most production APIs return data in pages, and a test that only checks page 1 misses 90% of the data.

Query Parameters
  • Pass as Python dict: params={"page": 1, "per_page": 10}
  • Multiple query params — all in one dict, requests handles encoding
  • Pagination — page and per_page to control results
  • Read total record count from response headers
Path Parameters & JSON Navigation
  • Path param in URL: f"{base_url}/users/{username}/repos"
  • Difference between path param and query param
  • Navigate nested JSON: response.json()["key"]["subkey"]
  • Loop through JSON array and extract specific fields
  • Pretty print: json.dumps(data, indent=4)
MODULE 04
POST, PUT, PATCH & DELETE Requests
requests.post · json=payload · file upload · requests.patch · requests.delete · CRUD
WHY THIS MODULE

Testing only GET requests is like testing a car by only checking if the doors open. The real value of API automation is in testing write operations — creating records, updating them, and deleting them. This module teaches you to complete a full CRUD cycle in code, which is what distinguishes a real API test suite from a collection of read-only scripts.

POST Request
  • requests.post(url, json=payload, headers=headers)
  • Payload as Python dict — auto-serialised to JSON
  • POST with file: files={"file": open("file.csv","rb")}
  • Expected response: 201 Created
PUT, PATCH & DELETE
  • requests.put() — full replacement of a resource
  • requests.patch() — partial update, only specified fields change
  • PUT vs PATCH — which to use and why
  • requests.delete(url, headers=headers)204 No Content
  • Verify delete with a follow-up GET — assert 404
  • Full CRUD flow: Create → Read → Update → Delete in one sequence
MODULE 05
Authentication & Headers
Bearer token · Authorization header · GitHub PAT · Basic auth · rate limiting
WHY THIS MODULE

Almost every real API requires authentication. Getting auth wrong means all your tests return 401 Unauthorized and nothing passes. This module teaches you to handle auth properly — store the token outside your code, build a reusable header, and test negative scenarios where the token is missing or wrong. Rate limiting is a common real-world problem you'll hit on the GitHub API, and knowing how to handle it prevents your test runs from getting blocked.

HTTP Headers
  • Pass headers as dict to every request
  • Content-Type: application/json for POST/PATCH body
  • Accept header — tell server what format you expect back
  • Custom headers — e.g. X-GitHub-Api-Version
Authentication
  • Bearer token: "Authorization": "Bearer <token>"
  • GitHub Personal Access Token (PAT) — generate, scope, and use
  • Basic Auth: requests.get(url, auth=("user","pass"))
  • Unauthenticated vs authenticated rate limits on GitHub API
  • Handle rate limit: X-RateLimit-Remaining header
  • Negative test — wrong token → assert 401 Unauthorized
MODULE 06
Response Assertions & JSON Validation
assert · status code · body keys · sorted() · positive/negative · AssertionError
WHY THIS MODULE

An API test without assertions is not a test — it is a script that blindly fires requests. This module is where your code becomes genuinely useful. You learn to verify that the API is actually doing what it is supposed to — correct status code, correct data, correct fields. Writing negative tests (sending bad input and verifying the error) is equally important and often what interviewers ask about first.

Status Code Assertions
  • assert response.status_code == 200
  • Custom failure message: assert x == y, "Expected 200 got 401"
  • Positive test: valid token → 200; negative: no token → 401
Response Body Validation
  • assert data["login"] == "expected_username"
  • assert "id" in data — key existence check
  • assert len(data) == expected_count
  • sorted(actual) == sorted(expected) — order-independent comparison
  • assert data["private"] == True — boolean field check
  • Positive and negative scenarios for each API endpoint
MODULE 07
GitHub REST API — Real-World Practice
GET /user · POST /user/repos · PATCH · DELETE · private/public · error scenarios
WHY THIS MODULE

Learning API automation on a mock server is useful, but it doesn't prepare you for the real world. GitHub's REST API is live, well-documented, requires real authentication, has rate limits, and returns real errors when you make mistakes. Practising all CRUD operations on it — and handling the edge cases — gives you interview-ready experience that you can speak to confidently because you actually did it on a real API.

GitHub API Endpoints
  • GET /user — authenticated user profile
  • GET /users/{username}/repos — list public repositories
  • GET /user/repos?type=private — list private repos (auth required)
  • POST /user/repos — create repo (name, private: true/false)
  • PATCH /repos/{owner}/{repo} — update name/description
  • DELETE /repos/{owner}/{repo} — delete repo
Test Scenarios
  • Create private repo → assert 201 and private: true
  • Create public repo → assert private: false
  • Duplicate repo name → assert 422 Unprocessable
  • No auth on write → assert 401 Unauthorized
  • Full CRUD cycle as one end-to-end sequence
MODULE 08
pytest Framework Introduction
@pytest.mark · conftest.py · @pytest.fixture · @pytest.mark.parametrize · pytest -m smoke
WHY THIS MODULE

Raw Python functions that call an API are not a test suite — pytest is what turns them into one. Markers let you run only smoke tests in 30 seconds or the full regression overnight. Fixtures eliminate duplicate setup code across hundreds of tests. Parametrize lets one test cover 20 data combinations automatically. This is the skeleton on which your entire framework is built.

pytest Basics
  • Test discovery: test_*.py files, def test_*() functions
  • Run all: pytest | Run file: pytest test_github.py
  • Verbose: pytest -v — see each test name and result
Markers, Fixtures & Parametrize
  • @pytest.mark.smoke, @pytest.mark.p1, @pytest.mark.p2
  • Run tagged subset: pytest -m smoke — only smoke tests execute
  • Register markers in pytest.ini to avoid warnings
  • @pytest.mark.parametrize — one test, multiple data sets
  • conftest.py — shared fixtures, no imports needed
  • @pytest.fixture with yield — setup before, teardown after
MODULE 09
Framework Architecture — Base Class & Config
BaseTest · base_url · get_headers() · fixture scope · session scope · helpers
WHY THIS MODULE

If every test file has its own copy of the base URL, auth token, and headers, then every time something changes you have 20 files to update. A base class solves this — you define everything once and all tests inherit it. This is the difference between a script collection and an actual maintainable framework. Interviewers always ask: "How do you manage common setup?" — this module gives you the answer.

Base Class Design
  • BaseTest class — base_url and headers in one place
  • Test classes inherit: class TestGetRepos(BaseTest)
  • Helper method: get_headers() builds auth headers automatically
  • One change in BaseTest propagates to all test classes instantly
conftest Fixtures & Helpers
  • Fixture scope — function, class, module, session
  • Session-scoped auth fixture — token loaded once, reused everywhere
  • Utility functions: response validator, JSON extractor
  • Project structure: tests/, utils/, config/, conftest.py
MODULE 10
Environment Management with config.ini
configparser · [global] · [staging] · [production] · os.path · zero code change switch
WHY THIS MODULE

Every professional project tests on at least two environments — staging and production. Hard-coding the staging URL means you have to find and replace it every time you want to test production. config.ini solves this cleanly: one file, one line change, the entire framework switches environments. This is a standard pattern in every real automation team and one of the first things asked about in job interviews.

config.ini Structure
  • [global] section with environment = staging
  • [staging], [production], [dev] — each with own base_url
  • Token stored per environment section
Reading Config in Python
  • import configparser
  • env = config["global"]["environment"]
  • base_url = config[env]["base_url"]
  • Resolve config path with os.path — works on any machine
  • Change one line → entire framework points to a different environment
MODULE 11
Test Reporting — Allure & HTML Reports
allure-pytest · @allure.step · pytest-html · shutil.rmtree · fixture teardown cleanup
WHY THIS MODULE

A test run that prints PASSED or FAILED to a terminal is not enough for a team. Managers want dashboards. Developers want to see exactly which step failed. QA leads want history and trends. Allure gives all of this. Adding step labels to your test functions costs 5 minutes but transforms a pass/fail result into a readable story of what the test did — and that is the difference between a useful report and one nobody looks at.

Allure Reports
  • pip install allure-pytest
  • Run with results: pytest --alluredir=allure-results
  • Serve report: allure serve allure-results
  • @allure.step("Step label") — readable step names in report
  • @allure.title(), @allure.description() decorators
  • Attach response body as report attachment
Report Management & Data Cleanup
  • pip install pytest-htmlpytest --html=report.html
  • Delete stale report folder: shutil.rmtree("allure-results")
  • Delete test data in fixture teardown with yield — cleanup always runs
  • Log API response time — surface slow endpoints in reports
MODULE 12
Framework Finalization & Interview Preparation
Full framework walkthrough · roles & responsibilities · project contribution · interview Q&A
WHY THIS MODULE

Knowing how to code tests is only half the job. The other half is being able to walk an interviewer through your framework, explain your contribution, describe your testing process end-to-end, and answer questions confidently. This module consolidates everything and focuses on exactly what hiring teams ask: "Show me your framework. What did you build? How do you handle environment switching? What is your process when a test fails?" This is where training turns into job readiness.

Complete Framework Structure
  • tests/ — test classes for GET, POST, PATCH, DELETE scenarios
  • utils/ — helper functions, response validators, data readers
  • config/config.ini — environment configuration file
  • conftest.py — shared fixtures, base setup, teardown cleanup
  • pytest.ini — marker registration, default run options
  • reports/ — Allure results and HTML report output folder
Interview Prep — Top Questions
How do you handle authentication in your framework?
Token is stored in config.ini. A get_headers() helper in the base class reads and attaches Authorization: Bearer <token> to every request — no test manages auth directly.
What is the difference between PUT and PATCH?
PUT replaces the entire resource — omitting a field clears it. PATCH updates only specified fields, leaving the rest unchanged. PATCH is safer for partial updates on GitHub's API.
How do you switch between environments?
Change environment = staging to environment = production in config.ini. The base class reads this and loads the correct base_url and token automatically — zero code changes.
What is conftest.py?
pytest's shared fixture file. Fixtures here are automatically available to all test files without any import. Auth headers, base URL, and teardown cleanup all live here.
How do you clean up data after tests?
Use @pytest.fixture with yield — create the resource before yield, delete it after. This guarantees cleanup runs even if the test fails, keeping each run independent.
What is your contribution to the framework?
Writing GET/POST/PATCH/DELETE automation scripts, building utility and helper functions, creating test data files, configuring config.ini for multi-environment, and integrating Allure reporting.